package com.wisedu.mobile.core.aspectj;

import com.wisedu.mobile.common.annotation.SLog;
import com.wisedu.mobile.common.domain.LoginUser;
import com.wisedu.mobile.common.domain.Syslog;
import com.wisedu.mobile.common.service.LogService;
import com.wisedu.mobile.common.service.TokenService;
import com.wisedu.mobile.common.utils.ServletUtils;
import com.wisedu.mobile.common.utils.SpringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 操作日志记录处理
 *
 * @author ruoyi
 */
@Aspect
@Component
public class LogAspect {
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    LogService logService;

    // 配置织入点
    @Pointcut("@annotation(com.wisedu.mobile.common.annotation.SLog)")
    public void logPointCut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            // 获得注解
            SLog slog = getAnnotationLog(joinPoint);
            if (slog == null) {
                return;
            }

            // 获取当前的用户
            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());

            // *========数据库日志=========*//
            Syslog sysLog = new Syslog();
            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();

            sysLog.setTag(slog.tag());
            sysLog.setSrc(className + "." + methodName + "()");
            sysLog.setMsg(slog.msg());

            sysLog.setIp(Lang.getIP(ServletUtils.getRequest()));

            sysLog.setCreateTime(new Date());

            sysLog.setType("after");
            if (e != null) {
                sysLog.setType("error");
                sysLog.setErrorMsg(e.getMessage().substring(0, 2000));
            }

            // 返回参数
            if(slog.result()) {
                sysLog.setResult(Json.toJson(jsonResult));
            }
            sysLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
            if (loginUser != null) {
                sysLog.setCreateBy(loginUser.getToken());
                sysLog.setUsername(loginUser.getUsername());
            }

            // 设置请求方式
            sysLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            String requestMethod = sysLog.getRequestMethod();
            if(slog.param()) {
                if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
                    String params = argsArrayToString(joinPoint.getArgs());
                    sysLog.setParam(Strings.brief(params, 100));
                } else {
                    Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                    sysLog.setParam(Strings.brief(paramsMap.toString(), 100));
                }
            }
            // 保存数据库
            logService.recordOper(sysLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }


    /**
     * 是否存在注解，如果存在就获取
     */
    private SLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(SLog.class);
        }
        return null;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = Json.toJson(paramsArray[i]);
                    params += jsonObj.toString() + " ";
                }
            }
        }
        return params.trim();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}
